package engine;
import java.util.HashMap;
import java.util.Map.Entry;


public class Project {

	private HashMap<String, ProjectProperty> characteristics;
	private static HashMap<String, double[]> multipliers;
	public static HashMap<String, Integer> indexValues;

	public Object tag;
	
	public Project(){
		characteristics = new HashMap<String, ProjectProperty>();
	}

	public String toString() {
		return "Project [size = " + String.valueOf(characteristics) +" ]";
	}

	public void addCharacteristic(ProjectProperty key){
		characteristics.put(key.getName(), key);
	}
	public ProjectProperty deleteCharacteristic(String string) {
		return characteristics.remove(string);
		
	}
	public double getEAF() {
		double ret = 1;
		
		for (Entry<String, ProjectProperty> ent : characteristics.entrySet()) {
			
			ProjectProperty pp = ent.getValue();
			
			if (!pp.isInteger())
				ret *= pp.getValue();
			
		}
		
		return ret;
	}

	public ProjectProperty getCharacteristic(String name){
		return characteristics.get(name);
	}
	

	public static class ProjectProperty implements Cloneable{
		String name;
		double value;

		public ProjectProperty(String name /*, String line*/) {
			this.name = name;
			
			//			
			//			String[] vals = line.split(" ");
			//			
			//			if (vals.length < 3)
			//				throw new IllegalArgumentException("Illegal property line: \""+line+"\"");
			//			
			//			this.index = index;
			//			this.name = vals[1];
			//			
			//			if (vals[2].equalsIgnoreCase("numeric"))
			//				value = Double.parseDouble(vals[2]);
			//			else {
			//				value = multipliers.get(name)[index];
			//				//value = new ProjectPropertyValueString(line, possibleValues)
			//			}
		}

		public ProjectProperty(String name, String value){
			this.name = name;
			set(value);
		}

		@Override
		protected Object clone() {
			ProjectProperty temp = new ProjectProperty(this.name);
			temp.value = this.value;
			return temp;
		}
		
		

		private boolean isInteger(){
			return (name.equals("LOC") || name.equals("ACT_EFFORT"));
		}

		public String getName() {
			return name;
		}
		
		

		public void set(String value) {
			
			if(!isInteger()){
				Object temp = indexValues.get(value);
				
				if (temp == null)
					;//lol
				else if (temp instanceof Integer)
					set((Integer)temp);				
			}else {
				this.value = Double.parseDouble(value);
			}
		}

		public void set(int value){
			if(!isInteger()){
				this.value = multipliers.get(name)[value];
			}else{
				
				this.value = value;
			}
		}

		public double getValue() {
			return value;
		}
	}

	public static abstract class ProjectPropertyValue implements Comparable<ProjectPropertyValue> {
		public abstract void set(String value);
	}
	
	public double compareTo(Project p2, HashMap<String, Double> range){
		double deltaSum = 0;
		int counter = 0;
		for(Entry<String, ProjectProperty> entry : characteristics.entrySet()){
			counter++;
			ProjectProperty pp = p2.getCharacteristic(entry.getKey());
			if(pp != null){
//				Logger.log("Crash(?) with name = " + pp.getName() +" and ranges = " + range);
				double r = range.get(pp.getName());
				
				if (r == 0) {
					deltaSum += 0;
				} else {
					deltaSum+=Math.pow((Math.abs(pp.getValue() - entry.getValue().getValue())/r),2);
				}
			}else{
//				deltaSum+=1;
				counter--;
			}
		}
		
		if (counter == 0)
			return 0.0;
		else{
			double ret = 1-Math.sqrt(deltaSum/counter); 
			return Math.max(ret, 0);
		}
	}

	/*public static class ProjectPropertyValueString extends ProjectPropertyValue {

		private String name;
		private String[] possibleValues;
		private int valueIndex;

		public ProjectPropertyValueString(String name, String[] possibleValues) {
			this.name = name;
			this.possibleValues = possibleValues;
			this.valueIndex = -1;
		}
		public void set(String value) {
			boolean ok = false;
			for (int i=0; i<possibleValues.length; i++) {
				if (possibleValues[i].equals(value)) {
					this.valueIndex = i;
					ok = true;
					break;
				}
			}
			if (!ok)
				throw new IllegalArgumentException("Couldn't set value \"" + value +"\" to propterty " + name);
		}

		@Override
		public int compareTo(ProjectPropertyValue other) {
			if (!(other instanceof ProjectPropertyValueString))
				throw new IllegalArgumentException("Can't compare two different property types");

			return 0;
		}
	}*/


	/*public static class ProjectPropertyValueInteger extends ProjectPropertyValue {

		@Override
		public int compareTo(ProjectPropertyValue other) {
			if (!(other instanceof ProjectPropertyValueInteger))
				throw new IllegalArgumentException("Can't compare two different property types");

			return 0;
		}

		@Override
		public void set(String value) {
			// TODO Auto-generated method stub

		}
	}*/

	/*
%    The numeric values of the effort multipliers are:
%
%      	        very						very	extra	productivity
%       	    low	low		nominal	high	high	high	range
%    ---------------------------------------------------------------------
%    acap	1.46   	1.19   	1.00   	0.86   	0.71   			2.06
%    pcap	1.42.  	1.17   	1.00   	0.86   	0.70 			1.67


%    aexp   1.29   	1.13   	1.00   	0.91   	0.82   			1.57
%    modp   1.24.  	1.10 	1.00 	0.91 	0.82 			1.34
%    tool   1.24 	1.10 	1.00 	0.91 	0.83 			1.49
%    vexp   1.21 	1.10 	1.00 	0.90 	  				1.34
%    lexp   1.14 	1.07 	1.00 	0.95 	  				1.20
%    sced   1.23 	1.08 	1.00 	1.04 	1.10 	  		e
%    stor   	       	    1.00   	1.06   	1.21   	1.56	-1.21
%    data   	    0.94 	1.00 	1.08 	1.16			-1.23
%    time   	  	    	1.00   	1.11   	1.30   	1.66	-1.30
%    turn   	    0.87   	1.00   	1.07   	1.15   			-1.32
%    virt   	    0.87   	1.00   	1.15   	1.30   			-1.49
%    rely   0.75	0.88	1.00 	1.15 	1.40			-1.87
%    cplx   0.70 	0.85 	1.00 	1.15 	1.30 	1.65	-2.36
	 */


	static {
		multipliers = new HashMap<String, double[]>();
		multipliers.put("ACAP", new double[]{1.46, 1.19, 1.00, 0.86, 0.71, -1});
		multipliers.put("PCAP", new double[]{1.42, 1.17, 1.00, 0.86, 0.70, -1});

		multipliers.put("AEXP", new double[]{1.29, 1.13, 1.00, 0.91, 0.82, -1});
		multipliers.put("MODP", new double[]{1.24, 1.10, 1.00, 0.91, 0.82, -1});
		multipliers.put("TOOL", new double[]{1.24, 1.10, 1.00, 0.91, 0.83, -1});
		multipliers.put("VEXP", new double[]{1.21, 1.10, 1.00, 0.90, -1,   -1});
		multipliers.put("LEXP", new double[]{1.14, 1.07, 1.00, 0.95, -1,   -1});
		multipliers.put("SCED", new double[]{1.23, 1.08, 1.00, 1.04, 1.10, -1});
		multipliers.put("STOR", new double[]{-1,   -1,   1.00, 1.06, 1.21, 1.56});
		multipliers.put("DATA", new double[]{-1,   0.94, 1.00, 1.08, 1.16, -1});
		multipliers.put("TIME", new double[]{-1,   -1,   1.00, 1.11, 1.30, 1.66});
		multipliers.put("TURN", new double[]{-1,   0.87, 1.00, 1.07, 1.15, -1});
		multipliers.put("VIRT", new double[]{-1,   0.87, 1.00, 1.15, 1.30, -1});
		multipliers.put("RELY", new double[]{0.75, 0.88, 1.00, 1.15, 1.40, -1});
		multipliers.put("CPLX", new double[]{0.75, 0.85, 1.00, 1.15, 1.30, 1.65});
		multipliers.put("JHOHNAHTAHN", new double[]{1.21, 1.19, 1.00, 0.86, 0.71, -1});

		
		indexValues = new HashMap<String, Integer>();
		indexValues.put("Very_Low", 0);
		indexValues.put("Low", 1);
		indexValues.put("Nominal", 2);
		indexValues.put("High", 3);
		indexValues.put("Very_High", 4);
		indexValues.put("Extra_High", 5);

	}

	
}
